home *** CD-ROM | disk | FTP | other *** search
/ ftp.qualcomm.com / 2014.06.ftp.qualcomm.com.tar / ftp.qualcomm.com / eudora / developers / emsapi / carbon_emsapi.sit.hqx / Macintosh API Support / mimetype.c < prev    next >
Text File  |  2001-03-08  |  11KB  |  371 lines

  1. /* ======================================================================
  2.  
  3.     Functions to manage MIME type data structures for use
  4.                  with Eudora translation API on the Mac.
  5.  
  6.     Filename:            mimetype.c
  7.     Last Edited:        March 7, 1997
  8.     Authors:            Laurence Lundblade, Myra Callen, Bob Fronabarger
  9.     Copyright:            1995, 1996 QUALCOMM Inc.
  10.     Technical support:    <emsapi-info@qualcomm.com>
  11. */
  12.  
  13. #include <string.h>
  14. #include "emsapi-mac.h"
  15. #include "mimetype.h"
  16. #include "copycat.h"
  17. #include "rfc822.h"
  18.  
  19. void    FreeParamType(emsMIMEparamH paramH);
  20.  
  21.  
  22. /* =========================================================================
  23.  *    Create a data structure to hold a MIME type. Add parameters later on with
  24.  *    calls to AddMimeParameter.
  25.  *
  26.  *    Args:     mimeType -- the main MIME type: e.g., text, application, image
  27.  *             subType -- the sub type: e.g., plain, octet-stream, jpeg
  28.  *              mimeV -- the MIME version number
  29.  *
  30.  *    Returns: Handle for the emsMIMEtype data structure
  31.  */
  32. emsMIMEtypeH MakeMimeType(const StringPtr mimeType,
  33.                             const StringPtr subType, const StringPtr mimeV)
  34. {
  35.     emsMIMEtype        mType, **mTypeHandle = nil;
  36.  
  37.     if (mimeType && subType) {
  38.         mType.size = sizeof(emsMIMEtype);
  39.         BlockMoveData(mimeType, mType.mimeType, mimeType[0] + 1);
  40.         BlockMoveData(subType, mType.subType, subType[0] + 1);
  41.         if (mimeV != nil)
  42.             BlockMoveData(mimeV, mType.mimeVersion, mimeV[0] + 1);
  43.         else
  44.             BlockMoveData("\p1.0", mType.mimeVersion, 4);
  45.         mType.params = nil;
  46.         mType.contentDisp[0] = '\0';
  47.         mType.contentParams = nil;
  48.     }
  49.     PtrToHand(&mType, (Handle*) &mTypeHandle, sizeof(emsMIMEtype));
  50.     return mTypeHandle;
  51. }
  52.  
  53.  
  54. /* =========================================================================
  55.  *  Create an emsMIMEtype structure to hold MIME information. Structure is
  56.  *  initialized to values provided in RFC822 content-type header line. This
  57.  *  includes all parameter name-value pairs.
  58.  *
  59.  *  NOTE: The user of this function is responsible for calling
  60.  *        FreeMimeType() on returned structure.
  61.  *
  62.  *  Args:     content_type [IN] The RFC822 content-type string to parse
  63.  *
  64.  *  Returns: Pointer to the created emsMIMEtype structure, nil if error.
  65.  */
  66. emsMIMEtypeH ParseMakeMimeType(const char *content_type)
  67. {
  68.     char            *cp;
  69.     char            *mime_type, *mime_subtype, *name, *value;
  70.     emsMIMEtypeH    mimeHdl;
  71.  
  72.     if (strnicmp(content_type, kContentTypeHdrCStr, kContentTypeHdrLen) != 0)
  73.         return nil;
  74.  
  75.     cp = (char*) content_type + kContentTypeHdrLen;
  76.     mime_subtype = nil;
  77.     mime_type = RFC822_ExtractToken(&cp);
  78.     if ((strlen(mime_type) > 0) && ((*cp++) == '/')) {
  79.         mime_subtype = RFC822_ExtractToken((char**) &cp);
  80.         if (strlen(mime_subtype) > 0) {    // We have a type/subtype
  81.             c2pstrcpy((StringPtr)mime_type,mime_type);
  82.             c2pstrcpy((StringPtr)mime_subtype,mime_subtype);
  83.             mimeHdl = MakeMimeType((StringPtr)mime_type, (StringPtr)mime_subtype, nil);
  84.  
  85.             DisposePtr(mime_type);
  86.             DisposePtr(mime_subtype);
  87.             if (mimeHdl) {
  88.                 name = value = nil;
  89.                 do {
  90.                     if ((*cp++) != ';')     // Skip semi-colon
  91.                         break;
  92.                     if (!(name = RFC822_ExtractToken(&cp)))
  93.                         break;
  94.                     if ((*cp++) != '=')        // Skip equals
  95.                         break;
  96.                     if (!(value = RFC822_ExtractToken(&cp)))
  97.                         break;
  98.                     if ((strlen(name) > 0) && (strlen(value) > 0))
  99.                     {
  100.                         c2pstrcpy((StringPtr)name,name);
  101.                         c2pstrcpy((StringPtr)value,value);
  102.                         AddMimeParameter(mimeHdl,(StringPtr) name,(StringPtr) value);
  103.                     }
  104.                     DisposePtr(name);
  105.                     DisposePtr(value);
  106.                     name = value = nil;
  107.                 } while (*cp);
  108.                 if (name)
  109.                     DisposePtr(name);
  110.                 if (value)
  111.                     DisposePtr(value);
  112.                 return mimeHdl;
  113.             }
  114.         }
  115.     }
  116.     if (mime_type)
  117.         DisposePtr((Ptr) mime_type);
  118.     if (mime_subtype)
  119.         DisposePtr((Ptr) mime_subtype);
  120.     return nil;
  121. }
  122.  
  123.  
  124. /* =========================================================================
  125.  *  Free a data structure holding a MIME type
  126.  *
  127.  *  Args:     Handle for the emsMIMEtype to be freed
  128.  */
  129. void FreeMimeType(emsMIMEtypeH mimeH)
  130. {
  131.     if (mimeH != nil) {
  132.         FreeParamType((**mimeH).params);
  133.         FreeParamType((**mimeH).contentParams);
  134.         DisposeHandle((Handle) mimeH);
  135.     }
  136. }
  137.  
  138.  
  139. /* =========================================================================
  140.  *    Convert a MIME type structure to a string in the format it is usually
  141.  *    presented in in a Content-Type: header.  This includes quoting the parameter
  142.  *    values and so on.
  143.  *
  144.  *    Args:     Handle for the emsMIMEtype
  145.  *
  146.  *    Returns: Handle to a block of ASCII formatted for use in a Content-Type: header
  147.  *             (note: it is not a Pascal string, nor a C string)
  148.  */
  149. Handle StringMimeType(emsMIMEtypeH mimeH)
  150. {
  151.     const char *kPrefixStr          = "Content-Type: ";
  152.     const char *kParamSepStr        = ";\r\n  ";
  153.     const char *kTypeSubtypeSepStr  = "/";
  154.     const char *kAttValueSepStr     = "=";
  155.     emsMIMEtypeP        mimeP;
  156.     emsMIMEparamH        paramHdl;
  157.     unsigned short        n, hLen;
  158.     Handle                hStr, h;
  159.     char                *cp;
  160.     Str255                theStr;
  161.  
  162.     if (mimeH == nil)
  163.         return nil;
  164.  
  165.     if (StrLength((**mimeH).mimeType) == 0 || StrLength((**mimeH).subType) == 0)
  166.         return nil;        // Both TYPE and SUBTYPE are required by RFC822
  167.  
  168.     HLock((Handle) mimeH);
  169.     mimeP = *mimeH;
  170.  
  171.     hLen = strlen(kPrefixStr);        // Calculate the length of the header string
  172.     hLen += RFC822_QuotedStrLen(mimeP->mimeType);
  173.     hLen += strlen(kTypeSubtypeSepStr);
  174.     hLen += RFC822_QuotedStrLen(mimeP->subType);
  175.  
  176.     paramHdl = mimeP->params;
  177.     while (paramHdl) {
  178.         hLen += strlen(kParamSepStr);
  179.         hLen += RFC822_QuotedStrLen((**paramHdl).name);
  180.         hLen += strlen(kAttValueSepStr);
  181.  
  182.         hStr = (**paramHdl).value;    // make string from value handle
  183.         n = GetHandleSize(hStr);
  184.         BlockMoveData(*hStr, theStr + 1, n);
  185.         theStr[0] = n;
  186.         hLen += RFC822_QuotedStrLen(theStr);
  187.  
  188.         paramHdl = (**paramHdl).next;
  189.     }
  190.  
  191.     hStr = NewHandle(hLen + 1);        // Allocate space for the header line
  192.     if (!hStr)
  193.         goto Exit;
  194.  
  195.     HLock(hStr);                    // Build the header line
  196.     cp = *hStr;
  197.     cp = strchr(strcpy(cp, kPrefixStr), '\0');
  198.     cp = RFC822_QuoteStrCpy(cp, mimeP->mimeType);
  199.     cp = strchr(strcpy(cp, kTypeSubtypeSepStr), '\0');
  200.     cp = RFC822_QuoteStrCpy(cp, mimeP->subType);
  201.  
  202.     paramHdl = mimeP->params;
  203.     while (paramHdl) {
  204.         cp = strchr(strcpy(cp, kParamSepStr), '\0');
  205.         cp = RFC822_QuoteStrCpy(cp, (**paramHdl).name);
  206.         cp = strchr(strcpy(cp, kAttValueSepStr), '\0');
  207.  
  208.         h = (**paramHdl).value;
  209.         n = GetHandleSize(h);
  210.         BlockMoveData(*h, theStr + 1, n);
  211.         theStr[0] = n;
  212.         cp = RFC822_QuoteStrCpy(cp, theStr);
  213.  
  214.         paramHdl = (**paramHdl).next;
  215.     }
  216.     HUnlock(hStr);
  217.     SetHandleSize(hStr, GetHandleSize(hStr) - 1);    // remove trailing null
  218. Exit:
  219.     HUnlock((Handle) mimeH);
  220.     return hStr;    // Return the header line
  221. }
  222.  
  223.  
  224. /* =========================================================================
  225.  *    Convenient MIME type matcher - saves locking some handles
  226.  *    If either type or subtype is nil, then it won't be checked.
  227.  *    values and so on.
  228.  *
  229.  *    Args:     mimeH -- The mime type to check
  230.  *             mType  -- The major MIME type to check
  231.  *             subtype -- The MIME subtype to check
  232.  *
  233.  *    Returns: 1 if the MIME type matches, 0 if not
  234.  */
  235. short MatchMimeType(emsMIMEtypeH mimeH, const StringPtr mType, const StringPtr subtype)
  236. {
  237.     Str63        theStr;
  238.     short        result = 1;
  239.  
  240.      if (mType != nil) {
  241.          CopyPP((**mimeH).mimeType, theStr);
  242.          result = EqualString(theStr, mType, false, true);
  243.      }
  244.     if (result && subtype != nil) {
  245.         CopyPP((**mimeH).subType, theStr);
  246.         result = EqualString(theStr, subtype, false, true);
  247.     }
  248.     return result;
  249. }
  250.  
  251. #pragma mark -
  252.  
  253. /* =========================================================================
  254.  *    Add a parameter to a MIME type
  255.  *
  256.  *    Might have to make the value parameter a Handle instead of a StringPtr
  257.  *    to accomodate items longer than 255 characters
  258.  *
  259.  *    Args:     mimeH -- Handle for the MIME type to add too
  260.  *             mType  -- Name of the parameter (Pascal string)
  261.  *             subtype -- Value of the parameter (currently a Pascal string)
  262.  */
  263. void AddMimeParameter(emsMIMEtypeH mimeH, const StringPtr name, const StringPtr value)
  264. {
  265.     emsMIMEparam    param;
  266.     emsMIMEparamH    ph, endPH;
  267.  
  268.     endPH = nil;    // Find last handle in the param list
  269.     for (ph = (**mimeH).params; ph != nil; ph = (**ph).next) {
  270.         endPH = ph;
  271.     }
  272.     param.size = sizeof(emsMIMEparam);
  273.     CopyPP(name, param.name);
  274.     param.value = nil;
  275.     PtrToHand(value + 1, ¶m.value, value[0]);
  276.     param.next = nil;
  277.     ph = nil;
  278.     PtrToHand(¶m, (Handle*) &ph, sizeof(emsMIMEparam));
  279.     
  280.     if (endPH == nil)        // It's an empty list
  281.         (**mimeH).params = ph;
  282.     else                    // Put at end of list
  283.         (**endPH).next = ph;
  284. }
  285.  
  286.  
  287. /* =========================================================================
  288.  *    Pick out a specific parameter from a MIME type
  289.  *
  290.  *    Args:     mimeH -- Handle to a struct ems_MIME_type
  291.  *             paramName -- string with name of parameter to look for
  292.  *
  293.  *  Returns: handle to string which is the value or nil (It is not a pascal string)
  294.  */
  295. Handle GetMimeParameter(emsMIMEtypeH mimeH, const StringPtr paramName)
  296. {
  297.     long            result;
  298.     Str63            theStr;
  299.     emsMIMEparam    **ph;
  300.  
  301.     for (ph = (**mimeH).params; ph != nil; ph = (**ph).next) {
  302.         CopyPP((**ph).name, theStr);
  303.         result = EqualString(theStr, paramName, false, true);
  304.         if (result)
  305.             return (**ph).value;
  306.     }
  307.     return nil;
  308. }
  309.  
  310.  
  311. /* =========================================================================
  312.  *  Remove a parameter from an existing emsMIMEtype structure. This structure
  313.  *  should be created using MakeMimeType().
  314.  *
  315.  *  NOTE: All input strings are COPIED before permanent use.
  316.  *
  317.  *    Args:     mimeH   [IN] Handle to the emsMIMEtype structure to altered
  318.  *              name    [IN] Name of the parameter to be removed
  319.  *
  320.  *  Returns: Boolean (true = success, false = failure)
  321.  */
  322. Boolean RemoveMimeParameter(emsMIMEtypeH mimeH, const StringPtr name)
  323. {
  324.     emsMIMEparamH    paramH, prevParamH;
  325.     Str63            theStr;
  326.  
  327.     if (!mimeH)
  328.         return false;
  329.  
  330.     paramH = (**mimeH).params;
  331.     prevParamH = nil;
  332.  
  333.     while (paramH != nil) {        /* Find the parameter */
  334.         CopyPP((**paramH).name, theStr);
  335.         if (EqualString(theStr, name, false, true))
  336.             break;
  337.         prevParamH = paramH;
  338.         paramH = (**paramH).next;
  339.     }
  340.     if (paramH == nil)
  341.         return false;         /* Not found */
  342.  
  343.     if (prevParamH == nil)        /* Removing first in list */
  344.         (**mimeH).params = (**paramH).next;
  345.     else
  346.         (**prevParamH).next = (**paramH).next;
  347.     DisposeHandle((**paramH).value);
  348.     DisposeHandle((Handle) paramH);
  349.  
  350.     return true;
  351. }
  352.  
  353.  
  354. /* =========================================================================
  355.  *  Private function used to free the parameter linked-list
  356.  *
  357.  *    Args:     mimeH   Handle to the parameter to be removed
  358.  */
  359. void FreeParamType(emsMIMEparamH paramH)
  360. {
  361.     emsMIMEparamH    nextParamH;
  362.  
  363.     while (paramH) {
  364.         nextParamH = (**paramH).next;
  365.         if ((**paramH).value != nil)
  366.             DisposeHandle((**paramH).value);
  367.         DisposeHandle((Handle) paramH);
  368.         paramH = nextParamH;
  369.     }
  370. }
  371.